#include<string.h>
#include<stdio.h> 
#include<assert.h>
#include<stdlib.h>
#include "html_tree.h"
#include "html_link.h"

#define MY_DEBUG 0


/* * create a child */
static struct Html_node * html_node_root;

static  struct Html_node * Create_child(struct Tree_node **root,struct Html_node *p)
{
	struct Html_node *ptr = p;
	struct Tree_node *child_node = NULL;
	struct Tree_node **sib_node = NULL;
	while(ptr != NULL)
	{
		switch(ptr->node_type)
		{
			case text:
				child_node = (struct Tree_node *)malloc(sizeof(struct Tree_node));
				child_node->element = ptr;
				child_node->child = NULL;

				/*
				 * insert the sibling node
				 */
				sib_node = &(*root)->child;
				while((*sib_node) != NULL)
				{
					sib_node = &(*sib_node)->sibling;
				}
				*sib_node = child_node;


				ptr = ptr->next;
				break;
			case start_tag:
				child_node = (struct Tree_node *)malloc(sizeof(struct Tree_node));
				child_node->element = ptr;
				child_node->child = NULL;

				/*
				 * insert the sibling node
				 */

				sib_node = &(*root)->child;
				while((*sib_node) != NULL)
				{
					sib_node = &(*sib_node)->sibling;
				}
				*sib_node = child_node;


				ptr = Create_child(&child_node,ptr->next);
				break;
			case end_tag:
				ptr = ptr->next;
				return ptr;
				break;
		}
	}
	return ptr;
}


/*
 * create a html tree
 */
void  Create_tree(struct Tree_node **root,char *html_file)
{
	genera_link_list(&html_node_root,html_file);

	(*root) = (struct Tree_node *)malloc(sizeof(struct Tree_node));
	(*root)->element = NULL;
	(*root)->child = NULL;
	(*root)->sibling = NULL;
	Create_child(root,html_node_root);
}


/*
 * get the child node of the root
 */
struct Tree_node * get_child(struct Tree_node *root)
{
	if(root == NULL)
		return NULL;
	return root->child;
}

/*
 * get the sibling node of the root
 */

struct Tree_node *get_sibling(struct Tree_node *root){
	if(root == NULL || root->element == NULL)
		return NULL;
	return root->sibling;
}

/*
 * traversal of the html_tree
 */

void traversal_to_string(struct Tree_node *root,int depth)
{

	if(root == NULL)
		return;

	if(root->element == NULL)
	{
		traversal_to_string(root->child,0);
		return;
	}
	

	int i;
	struct Html_node *ptr = root->element;
	if(ptr == NULL)
		return;

	if(ptr->node_type == start_tag)
	{

		for(i = 0;i<depth;i++)
			printf(" ");
		printf("<%s",tags[ptr->name_index])	;

		struct Attr_node *att_node = ptr->attr;			
		while(att_node != NULL)
		{
			printf(" %s=%s",att_node->name,att_node->value);
			att_node = att_node->next;
		}
		printf(">\n");
/*
 * traveral of the child
 */
		traversal_to_string(root->child,depth+2);

		for(i = 0;i<depth;i++)
			printf(" ");
		printf("</%s>\n",tags[ptr->name_index]);

		/*
		 * traversal of the sibling
		 */
		traversal_to_string(root->sibling,depth);
	}
	else if(ptr->node_type == text)
	{
		for(i = 0;i<depth;i++)
			printf(" ");
		printf("%s\n",ptr->text_ptr);
	}
}


/*
 * return the value of specified attr of a tree_node,the root->node_type = star_tag
 */

char * get_attr_value(struct Tree_node *root, char *attr_name)
{

	if(root == NULL || root->element == NULL || (root->element)->node_type != start_tag)
		return NULL;
	struct Attr_node *ptr = (root->element)->attr;
	while(ptr != NULL)
	{
		if(strcmp(attr_name,ptr->name) == 0)
			return ptr->value;
		ptr = ptr->next;
	}
	return NULL;
}





/*
 *   return a pointer pointing to header of the linked list of specified attr_name
 */
void  get_attr_value_list(struct Tree_node *root,struct linked_list_attr_node **head, char *attr_name)
{
	if(root == NULL)
		return;
	if(root->element == NULL)
	{
		get_attr_value_list(root->child,head,attr_name);
		return;
	}
	struct linked_list_attr_node **ptr = head;
	struct Html_node *p = root->element;

	if(p->node_type ==  start_tag)
	{
		while(*ptr != NULL)
			ptr = &(*ptr)->next;

		char *p_str = get_attr_value(root,attr_name);
		if(p_str != NULL)
		{
			*ptr = (struct linked_list_attr_node *)malloc(sizeof(struct linked_list_attr_node));
			(*ptr)->str = p_str;
			(*ptr)->next = NULL;

			assert((*ptr)->str != NULL);
			
			ptr = &(*ptr)->next;
		}
		
		get_attr_value_list(root->child,ptr,attr_name);
		get_attr_value_list(root->sibling,ptr,attr_name);
	}
	else
	{
		get_attr_value_list(root->sibling,ptr,attr_name);
	}
}


/*
 * return the text value if Tree_node->ellment->node_type == text
 */
char * get_text_value(struct Tree_node *root)
{
	if(root == NULL || root->element == NULL)
		return NULL;

	if((root->element)->node_type == text){
		return (root->element)->text_ptr;
	}
	return NULL;
}

/*
 * return a pointer pointing to header of the linnked list of specified text,only process the child of the root
 */
void get_text_value_list(struct Tree_node *root,struct linked_list_text_node **head )
{
	if(root == NULL)	
		return ;

	struct Html_node *ptr = root->element;
	struct linked_list_text_node **p = head;

	if(root->element == NULL)
	{
		get_text_value_list(root->child,head);
		return ;
	}

	if(ptr->node_type == start_tag)
	{
		get_text_value_list(root->child,p);
		get_text_value_list(root->sibling,p);
		return;
	}
	else{
		while(*p != NULL)
		{
			p = &(*p)->next;
		}

		*p = (struct linked_list_text_node *)malloc(sizeof(struct linked_list_text_node));
		if(*p == NULL)
		{
			perror("eroor !malloc error!");
			puts("line 257----");
			return;
		}
		(*p)->str = ptr->text_ptr;
		(*p)->next = NULL;
		get_text_value_list(root->sibling,&(*p)->next);
	}
}


/*
 * return the pointer which points to the Tree_node whose start_tag is  my_tag,if there are a few Tree_node,return the header pointer of
 * the linked list
 */
void get_content_by_tag(struct Tree_node *root,struct linked_list_tree_node **head, char *my_tag)
{
	if(root == NULL) 
		return ;
	if(root->element == NULL)
	{
		get_content_by_tag(root->child,head,my_tag);
		return;
	}
	struct Html_node *ptr = root->element;
	struct linked_list_tree_node **p = head;
	if(ptr->node_type == start_tag)
	{

#if 0 
			puts("debuging.............line 277");
			printf("tags[ptr->name_index] = %s\n",tags[ptr->name_index]);
			printf("my_tag = %s\n",my_tag);
#endif

		if(strcmp(tags[ptr->name_index],my_tag)==0)
		{
			while(*p != NULL)	
			{
				p = &(*p)->next;
			}
			*p = (struct linked_list_tree_node *)malloc(sizeof(struct linked_list_tree_node));
			(*p)->element = root;
			(*p)->next = NULL;
			get_content_by_tag(root->sibling,&(*p)->next,my_tag);
			get_content_by_tag(root->child,&(*p)->next,my_tag);
		}
		else{
			get_content_by_tag(root->sibling,p,my_tag);
			get_content_by_tag(root->child,p,my_tag);
		}
	}
	else
	{
		get_content_by_tag(root->sibling,p,my_tag);
	}

}


/*
 * return the pointer which points to a Tree_node whose start_tag's attr's id == my_id
 */

struct Tree_node * get_content_by_id(struct Tree_node *root,char *my_id)
{

	if(root == NULL)
		return NULL;
	if(root->element == NULL)
		return get_content_by_id(root->child,my_id);
	struct Tree_node *ptr = NULL ;
	struct Html_node *p = NULL;
	
	if((root->element)->node_type == start_tag)
	{
		p = root->element;
		struct Attr_node *attr_ptr = p->attr;
		while(attr_ptr != NULL)
		{
			if(strcmp(attr_ptr->name,"id") == 0)
			{
				if(strcmp(attr_ptr->value,my_id) == 0)
					return root;
			}
			attr_ptr = attr_ptr->next;
		}
		ptr = get_content_by_id(root->child,my_id);
		if(ptr != NULL)
			return ptr;
		ptr = get_content_by_id(root->sibling,my_id);
		if(ptr!=NULL)
			return ptr;
	}
	else{
		ptr = get_content_by_id(root->sibling,my_id);
		if(ptr!=NULL)	
			return ptr;
	}
	return NULL;
}

/*
 * free the memory of the html_tree
 */
void free_tree(struct Tree_node *root)
{

	if(root == NULL)
		return;
	if(root->element == NULL)
	{
		struct Html_node *head = (root->child)->element;
		free_tree(root->child);
		free(root);
		destroy(head);
		return;
	}
	free_tree(root->child);
	free_tree(root->sibling);
	free(root);

}
